#pragma once

#include <string>
#include <vector>
#include <memory>

#include "rtda/frame.h"
#include "rtda/heap/object.h"
#include "rtda/thread.h"
#include "native/registry.h"

namespace jvm {
    namespace lang {

        class StackTraceElement {
        private:
            std::string _file_name;
            std::string _class_name;
            std::string _method_name;
            int _line_number;

        public:
            StackTraceElement(const std::string& fileName, const std::string& className,
                const std::string& methodName, int lineNumber)
                : _file_name(fileName), _class_name(className),
                _method_name(methodName), _line_number(lineNumber) {}

            std::string toString() const {
                return _class_name + '.' +
                    _method_name + ".(" +
                    _file_name + '.' +
                    std::to_string(_line_number) + ')';
            }
        };


        std::vector<std::shared_ptr<StackTraceElement>> createStackTraceElements(
            heap::ObjectPtr pTObj, std::shared_ptr<rtda::Thread> pThread);

        int distanceToObject(std::shared_ptr<heap::Class> pClass);

        std::shared_ptr<StackTraceElement> createStackTraceElement(std::shared_ptr<rtda::Frame> pFrame);

        class ThrowableNative
        {
        private:
            static const std::string JL_THROWABLE;

        public:
            // private native Throwable fillInStackTrace(int dummy);
            static void fillInStackTrace(std::shared_ptr<rtda::Frame> pFrame);

            static void init()
            {
               native::Registry::registerMethod(JL_THROWABLE, "fillInStackTrace","(I)Ljava/lang/Throwable;", &fillInStackTrace);
            }

        };


    } // namespace lang
} // namespace jvm